package service;

import java.util.Date;

import com.jfinal.aop.Aop;
import com.jfinal.kit.HashKit;
import com.jfinal.kit.Kv;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.ehcache.CacheKit;

import model.LoginLog;
import model.Session;
import model.User;

public class LoginService extends BaseService{
    static UserService userService = Aop.get(UserService.class);

    // 存放登录用户的缓存名称
    public static final String loginUserCacheName = "loginUser";
    public static final String cookieSessionIdName = "token";

    /**
     * 通过账号和密码登录后台
     * 登录成功返回sessionId与cookie保存时间，否则返回一个错误msg
     */
    public Ret login(String userName, String password, boolean keepLogin, String loginIp){
    	User loginUser = User.dao.findFirstByName(userName);
        if(loginUser == null || loginUser.getIsDelete() ){
            return fail("用户名或密码不正确");
        }
        
        Kv kv = CacheKit.get("system", "loginError_" + loginUser.getId() );
        
        if (null != kv && kv.getInt("times") > 5 ) {
        	if (kv.getLong("expireTime") > System.currentTimeMillis()) {
        		return fail("密码次数错误过多，24小时后再试");
			}
			CacheKit.remove("system", "loginError_" + loginUser.getId());
		}
        String hashedPass = HashKit.sha256(password + loginUser.getSalt());
        if (!loginUser.getPassword().equals(hashedPass)) {
        	if (null == kv) {
    			kv = Kv.by("times", 0);
    		}
        	kv.set("times" , kv.getInt("times") + 1).set("expireTime" , System.currentTimeMillis() + 24*60*60*1000);
        	CacheKit.put("system", "loginError_" + loginUser.getId(), kv);
            return fail("用户名或密码不正确");
        }

        //如果用户勾选保持登录, sessionId保存七天，否则保存两个小时
        int maxAgeInSeconds = keepLogin? 7 * 24 * 60 * 60 : 120 * 60;
        //随机获取一个唯一的sessionId
        String sessionId = StrKit.getRandomUUID();

        //如果用户勾选保持登录，将session存到数据库
        Date expired = new Date(System.currentTimeMillis() + maxAgeInSeconds * 1000);
        Ret ret = createSession(sessionId, loginUser.getId() , expired);
        if(ret.isFail()){
            return ret;
        }

        loginSuccess(sessionId, loginUser, loginIp);
        return Ret.ok(cookieSessionIdName, sessionId);
    }

    /**
     * 通过 sessionId 获取登录用户信息
     * sessoin表结构：session(id, accountId, expireAt)
     *
     * 1：先从缓存里面取，如果取到则返回该值，如果没取到则从数据库里面取
     * 2：在数据库里面取，如果取到了，则检测是否已过期，如果过期则清除记录，
     *     如果没过期则先放缓存一份，然后再返回
     */
    public User loginWithSessionId(String sessionId, String loginIp) {
        Session session = Session.dao.findById(sessionId);
        // session 不存在
        if (session == null) {
            return null;
        }
        // session 已过期，在数据库中删除session。还需要定时清空已经过期的session
        if (session.isExpired()) {
            session.delete();
            return null;
        }

        User loginUser = User.dao.findById(session.getUserId());
        // 找到 loginAccount 并且 是正常状态 才允许登录
        if (loginUser != null && !loginUser.getIsDelete()) {
            loginSuccess(sessionId, loginUser, loginIp);
            return loginUser;
        }
        return null;
    }

    /**
     *  登录成功后执行一些操作
     */
    private void loginSuccess(String sessionId, User loginUser, String loginIp){
    	Date lastLoginTime = new Date();
    	loginUser.setLastLoginTime(lastLoginTime);	
    	loginUser.setSessionId(sessionId);
    	loginUser.update() ;
       
        //将登录用户保存到缓存
        CacheKit.put(loginUserCacheName, sessionId, loginUser);
        //创建登录日志
        LoginLog.dao.save( loginUser.getId() , lastLoginTime, sessionId, loginIp );
    }

    /**
     * 创建session
     */
    public Ret createSession(String sessionId, Long userId , Date maxAgeInSeconds){
        Session session = new Session();
        session.setId(sessionId);
        session.setUserId(userId);
        session.setExpireTime(maxAgeInSeconds);
        return session.save() ? ok() : fail( "保存session到数据库失败，请联系管理员");
    }

    /**
     * 退出登录
     */
    public void logout(String sessionId) {
        if (sessionId != null) {
            CacheKit.remove(loginUserCacheName, sessionId);
            Session.dao.deleteById(sessionId);
        }
    }
}
